/*
 * Copyright (C) 2000-2008 Jens Nixdorf and various contributors
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies of the Software, its documentation and marketing & publicity
 * materials, and acknowledgment shall be given in the documentation, materials
 * and software packages that this Software was used.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
 * THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
 * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
package org.mopore.jat.core.fadingmessage.calibration.visual;

import java.awt.Composite;
import java.awt.Frame;
import java.awt.Graphics2D;
import java.awt.GraphicsDevice;
import java.awt.GraphicsEnvironment;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferStrategy;
import java.awt.image.BufferedImage;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.mopore.jat.core.fadingmessage.calibration.CalibrationInfo;
import org.mopore.jat.core.fadingmessage.calibration.ICalibtrationInfoReciever;
import org.mopore.jat.gui.SingleRoundCornerRectangleFactory.CornerType;
import org.mopore.jat.util.ImageService;

public class VisualCalibtration implements Runnable, IScreenOperator, ICalibtratable {

    private boolean wanTolive = true;

    private Frame frame;

    private BufferedImage screenImage;

    private BufferStrategy strategy;

    private int screenWidth;

    private int screenHeight;

    private CalibrationState calibtrationState;

    private final Log log = LogFactory.getLog(getClass().getName());

    private final CalibrationPainter calibtrationPainter;
    
    private final InfoPainter infoPainter;

    private final HazePainter hazePainter;

    private boolean operating;

	private final ICalibtrationInfoReciever reciever;

    public VisualCalibtration( ICalibtrationInfoReciever reciever, 
    		CornerType cornerType, int horizontalOffset, int verticalOffset) 
    	throws Exception {

        this.reciever = reciever;
		Toolkit toolkit = Toolkit.getDefaultToolkit();
        screenWidth = (int) toolkit.getScreenSize().getWidth();
        screenHeight = (int) toolkit.getScreenSize().getHeight();

        Robot robot = new Robot();
        Rectangle rectangle = new Rectangle(0, 0, screenWidth, screenHeight);
        BufferedImage caputredImage = robot.createScreenCapture(rectangle);
        screenImage = ImageService.blackWhite( caputredImage );
        
        // Determine if page flipping is supported
        GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
        GraphicsDevice gd = ge.getDefaultScreenDevice();

        // Create a window for full-screen mode
        frame = new MyFrame(gd.getDefaultConfiguration(), this, this );
        frame.setUndecorated(true);

        frame.setSize(gd.getDisplayMode().getWidth(), gd.getDisplayMode().getHeight());
        frame.setLocation(0, 0);
        frame.setVisible(true);

        frame.requestFocus();
        frame = StrategyChooser.loadDefaultStrategy(frame);
        strategy = frame.getBufferStrategy();

        this.operating = false;
        this.calibtrationState = new CalibrationState( cornerType, 
        		horizontalOffset, verticalOffset, screenWidth, screenHeight );
        this.calibtrationPainter = new CalibrationPainter();
        this.infoPainter = new InfoPainter();
        this.hazePainter = new HazePainter(screenWidth, screenHeight);

        VisualCalibtrationAdapter adapter = new VisualCalibtrationAdapter(this, this );
        frame.addMouseListener(adapter);
        frame.addMouseMotionListener(adapter);
        frame.addKeyListener(adapter);
        frame.addMouseWheelListener(adapter);
    }

    private void paint(Graphics2D g) {

        final Composite origComposite = g.getComposite();
        g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g.drawImage(screenImage, null, 0, 0);

        hazePainter.paintHaze(g, origComposite);

        infoPainter.paintInfo(g, origComposite, calibtrationState);
        calibtrationPainter.paintCalibtration(g, origComposite, calibtrationState);
    }


    public void setOperating(boolean operating) {
        this.operating = operating;
    }

    /**
     * 
     */
    private void release() {
    	frame.dispose();
    	CalibrationInfo calibrationInfo = new CalibrationInfo();
    	calibrationInfo.setCornerType( calibtrationState.getCornerType() );
    	calibrationInfo.setHorizontalOffset( calibtrationState.getHorizontalOffset() );
    	calibrationInfo.setVerticalOffset( calibtrationState.getVerticalOffset() );
    	calibrationInfo.setInitCalibration( false );
    	reciever.recieveCalibrationInfo( calibrationInfo );
    }


    public void finishCalibration() {
    	calibtrationState.calibtrationFinished();
    }

    public void run() {

        // Draw loop
        while (wanTolive) {
            // Get screen size

            // Get graphics context for drawing to the window
            Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
            paint( g );

            // done drawing
            g.dispose();

            // flip the back buffer to the screen
            strategy.show();

            if (!operating ) {
            	// make a break because no need to react
                try {
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    log.error("can not sleep", e);
                }
            }

            if ( calibtrationPainter.isFinished() ) {
                wanTolive = false;
            }

        }
        log.debug("no reason to live anymore...");
        release();
    }

	@Override
	public CalibrationState getCurrentCalibtration() {
		return calibtrationState;
	}

	@Override
	public boolean isOperating() {
		return operating;
	}

	
	public static void main(String[] args) throws Exception {
		
		CornerType cornerType = CornerType.LOWER_RIGHT;
		int horizontalOffset = 20;
		int verticalOffset = 24;
		
		ICalibtrationInfoReciever reciever = new ICalibtrationInfoReciever(){

			@Override
			public void recieveCalibrationInfo(CalibrationInfo calibrationInfo) {
				int horizontalOffset = calibrationInfo.getHorizontalOffset();
				int verticalOffset = calibrationInfo.getVerticalOffset();
				CornerType cornerType = calibrationInfo.getCornerType();
				System.out.println( "h: " + horizontalOffset);
				System.out.println( "v: " + verticalOffset );
				System.out.println( "corner: " + cornerType );
			}
		};
		
		Runnable runnable = new VisualCalibtration( reciever, cornerType, 
				horizontalOffset, verticalOffset );
		Thread t = new Thread(runnable);
		t.start();
	}
}
